/****************************************************************************\
*                                                                            *
*  Copyright 2008 The CAnt2 Project (http://code.google.com/p/cant2)         *
*                                                                            *
*  Licensed under the Apache License, Version 2.0 (the "License");           *
*  you may not use this file except in compliance with the License.          *
*  You may obtain a copy of the License at                                   *
*                                                                            *
*      http://www.apache.org/licenses/LICENSE-2.0                            *
*                                                                            *
*  Unless required by applicable law or agreed to in writing, software       *
*  distributed under the License is distributed on an "AS IS" BASIS,         *
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
*  See the License for the specific language governing permissions and       *
*  limitations under the License.                                            *
*                                                                            *
\****************************************************************************/

#include "UnitTest.h"

#include <sstream>
#include <stdexcept>
#include <vector>

#include "CAnt2/src/core/xml.h"

/****************************************************************************/

namespace {

    class ExpectXmlEvent : public IXmlParseEvent
    {
    public:
        ExpectXmlEvent()
            : p ( 0 )
        {
        }
    
        void ExpectElementBegin ( const wchar_t* name )
        {
            const Event& e = events.at(p);
            if ( e.first != EBegin ) throw std::runtime_error ( "Failed." );
            if ( e.second.first != name ) throw std::runtime_error ( "Failed." );
            ++p;
        }
    
        void ExpectAttribute ( const wchar_t* name, const wchar_t* value )
        {
            const Event& e = events.at(p);
            if ( e.first != EAttrib ) throw std::runtime_error ( "Failed." );
            if ( e.second.first != name ) throw std::runtime_error ( "Failed." );
            if ( e.second.second != value ) throw std::runtime_error ( "Failed." );
            ++p;
        }
    
        void ExpectElementEndAttributes ( const wchar_t* name )
        {
            const Event& e = events.at(p);
            if ( e.first != EAttribEnd ) throw std::runtime_error ( "Failed." );
            if ( e.second.first != name ) throw std::runtime_error ( "Failed." );
            ++p;
        }
    
        void ExpectElementEnd   ( const wchar_t* name )
        {
            const Event& e = events.at(p);
            if ( e.first != EEnd ) throw std::runtime_error ( "Failed." );
            if ( e.second.first != name ) throw std::runtime_error ( "Failed." );
            ++p;
        }
    
        void ExpectEndOfFile    ()
        {
            const Event& e = events.at(p);
            if ( e.first != EEof ) throw std::runtime_error ( "Failed." );
            ++p;
            if ( p != events.size() ) throw std::runtime_error ( "Failed." );
        }
    
    private:
        virtual void ElementBegin ( const wchar_t* name )
        {
            events.push_back ( std::make_pair ( EBegin, std::make_pair ( std::wstring ( name ) , std::wstring() ) ) );
        }
    
        virtual void ElementEnd ( const wchar_t* name )
        {
            events.push_back ( std::make_pair ( EEnd, std::make_pair ( std::wstring ( name ) , std::wstring() ) ) );
        }
    
        virtual void Attribute ( const wchar_t* name, const wchar_t* value )
        {
            events.push_back ( std::make_pair ( EAttrib, std::make_pair ( std::wstring ( name ) , std::wstring ( value ) ) ) );
        }
    
        virtual void ElementEndAttributes ( const wchar_t* name )
        {
            events.push_back ( std::make_pair ( EAttribEnd, std::make_pair ( std::wstring ( name ) , std::wstring() ) ) );
        }
    
        virtual void EndOfFile()
        {
            events.push_back ( std::make_pair ( EEof, std::make_pair ( std::wstring () , std::wstring() ) ) );
        }
    
    public:
        enum Code
        {
            EBegin,
            EEnd,
            EAttrib,
            EAttribEnd,
            EEof,
        };
        typedef std::pair < Code, std::pair < std::wstring, std::wstring > > Event;
        std::vector < Event > events;
        size_t p;
    };

}

/****************************************************************************/

namespace {

    TEST ( testXmlParser )
    {
        std::istringstream ss ( "<x:tag v1 = \"foo\" v2='bar' ><!--xxxx--></x:tag ><y:tag />" );
        ExpectXmlEvent expect;
        XmlParser xmlParser ( ss, expect );

        CHECK_NOTHROW ( xmlParser.Run() );

        CHECK_NOTHROW ( expect.ExpectElementBegin(L"x:tag") );
        CHECK_NOTHROW ( expect.ExpectAttribute(L"v1",L"foo") );
        CHECK_NOTHROW ( expect.ExpectAttribute(L"v2",L"bar") );
        CHECK_NOTHROW ( expect.ExpectElementEndAttributes(L"x:tag") );
        CHECK_NOTHROW ( expect.ExpectElementEnd(L"x:tag") );
        CHECK_NOTHROW ( expect.ExpectElementBegin(L"y:tag") );
        CHECK_NOTHROW ( expect.ExpectElementEndAttributes(L"y:tag") );
        CHECK_NOTHROW ( expect.ExpectElementEnd(L"y:tag") );
        CHECK_NOTHROW ( expect.ExpectEndOfFile() );
    }

};

